home *** CD-ROM | disk | FTP | other *** search
/ Gamers Delight 2 / Gamers Delight 2.iso / Aminet / game / role / pinfocom_3_0.lha / Source / stream.c < prev    next >
C/C++ Source or Header  |  1992-10-22  |  17KB  |  711 lines

  1. /* stream.c
  2.  *
  3.  *  ``pinfocom'' -- a portable Infocom Inc. data file interpreter.
  4.  *  Copyright (C) 1987-1992  InfoTaskForce
  5.  *
  6.  *  This program is free software; you can redistribute it and/or modify
  7.  *  it under the terms of the GNU General Public License as published by
  8.  *  the Free Software Foundation; either version 2 of the License, or
  9.  *  (at your option) any later version.
  10.  *
  11.  *  This program is distributed in the hope that it will be useful,
  12.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  *  GNU General Public License for more details.
  15.  *
  16.  *  You should have received a copy of the GNU General Public License
  17.  *  along with this program; see the file COPYING.  If not, write to the
  18.  *  Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  */
  20.  
  21. /*
  22.  * $Header: RCS/stream.c,v 3.0 1992/10/21 16:56:19 pds Stab $
  23.  */
  24.  
  25. #include <stdio.h>
  26. #include <string.h>
  27. #include <ctype.h>
  28. #include <errno.h>
  29.  
  30. #include <signal.h>
  31.  
  32. #include "infocom.h"
  33.  
  34. #ifndef free
  35. extern void free();
  36. #endif
  37.  
  38. #ifdef NEED_ERRNO
  39. extern int errno;
  40. #endif
  41.  
  42. /*
  43.  * Global Variables
  44.  */
  45.  
  46. /*
  47.  * Variable:    scr_usage
  48.  *
  49.  * Description:
  50.  *      This variable should contain a usage string for any extra
  51.  *      command-line options available through this terminal
  52.  *      interface.
  53.  */
  54. const char *scr_usage       = "";
  55.  
  56. /*
  57.  * Variable:    scr_long_usage
  58.  *
  59.  * Description:
  60.  *      This variable should contain a more verbose usage string
  61.  *      detailing the command-line options available through this
  62.  *      terminal interface, one option per line.
  63.  */
  64. const char *scr_long_usage  = NULL;
  65.  
  66. /*
  67.  * Variable:    scr_opt_list
  68.  *
  69.  * Description:
  70.  *      This variable should contain a getopt(3)-style option list for
  71.  *      any command-line options available through this terminal
  72.  *      interface.
  73.  */
  74. const char *scr_opt_list    = "";
  75.  
  76. /*
  77.  * Local Variables
  78.  */
  79. static FILE *scr_fp=NULL;
  80.  
  81. static int scr_columns=80, scr_indent=0;
  82. static int scr_lines=24, scr_lineco=0, scr_context=0;
  83.  
  84.  
  85. /*
  86.  * Function:    scr_cmdarg()
  87.  *
  88.  * Arguments:
  89.  *      argc        number of original arguments
  90.  *      argvp       pointer to array of strings containing args
  91.  *
  92.  * Returns:
  93.  *      Number of new arguments.
  94.  *
  95.  * Description:
  96.  *      This function is called before any command line parsing is
  97.  *      done.  Any terminal interface-specific arguments should be
  98.  *      pulled out of the argv list and any extra arguments obtained
  99.  *      from resource files or wherever should be added.  Note that
  100.  *      (*argvp)[0] must be the command name and (*argvp)[argc] must
  101.  *      be a null pointer.
  102.  *
  103.  * Notes:
  104.  */
  105. int
  106. scr_cmdarg A2(int, argc, char ***, argvp)
  107. {
  108.     return (argc);
  109. }
  110.  
  111.  
  112. /*
  113.  * Function:    scr_getopt()
  114.  *
  115.  * Arguments:
  116.  *      c           option found
  117.  *      arg         option argument (if requested)
  118.  *
  119.  * Description:
  120.  *      This function is called whenever a command-line option
  121.  *      specified in scr_opt_list (above) is found on the command
  122.  *      line.
  123.  */
  124. void
  125. scr_getopt A2(int, c, const char *, arg)
  126. {
  127. }
  128.  
  129.  
  130. /*
  131.  * Function:    scr_setup()
  132.  *
  133.  * Arguments:
  134.  *      margin      # of spaces in the right margin.
  135.  *      indent      # of spaces in the left margin.
  136.  *      scr_sz      # of lines on the screen.
  137.  *      context     # of lines of context to keep when scrolling
  138.  *
  139.  * Returns:
  140.  *      Width of screen output for informational printing (not used if
  141.  *      game is to be played).
  142.  *
  143.  * Description:
  144.  *      This function should set up generic items in the screen
  145.  *      interface that may need to be done before *any* output is
  146.  *      done.
  147.  *
  148.  *      If SCR_SZ is not 0, then this function must use SCR_SZ as the
  149.  *      number of lines the screen can hold at once, no matter what it
  150.  *      may infer otherwise.  If SCR_SZ is 0, then the function must
  151.  *      figure the size of the screen as best it can.
  152.  *
  153.  * Notes:
  154.  *      Any terminal initialization needed only for actually playing
  155.  *      the game should go in scr_begin(), not here.
  156.  */
  157. int
  158. scr_setup A4( int, margin,
  159.               int, indent,
  160.               int, scr_sz,
  161.               int, context )
  162. {
  163.     scr_columns -= margin + indent;
  164.  
  165.     if (scr_sz)
  166.         scr_lines = scr_sz;
  167.  
  168.     scr_lines  -= context + 2;
  169.     scr_lineco -= context - 1;
  170.     scr_context = context;
  171.     scr_indent  = indent;
  172.  
  173.     return (scr_columns);
  174. }
  175.  
  176.  
  177. /*
  178.  * Function:    scr_shutdown()
  179.  *
  180.  * Description:
  181.  *      This function will be called just before we exit.
  182.  */
  183. void
  184. scr_shutdown()
  185. {
  186. }
  187.  
  188.  
  189. /*
  190.  * Function:    scr_begin()
  191.  *
  192.  * Arguments:
  193.  *      game    The game datafile we're about to execute.
  194.  *
  195.  * Description:
  196.  *      This function should perform terminal initializations we need
  197.  *      to actually play the game.
  198.  */
  199. void
  200. scr_begin()
  201. {
  202.     int i;
  203.  
  204.     /*
  205.      * Scroll enough so that the saved context lines for the very
  206.      * first screen are blank.
  207.      */
  208.     for (i = scr_context; i != 0; --i)
  209.         putchar('\n');
  210. }
  211.  
  212.  
  213. /*
  214.  * Function:    scr_end()
  215.  *
  216.  * Description:
  217.  *      This function will be called after the last line is printed
  218.  *      but before we exit, *only* if scr_begin() was called (*not* if
  219.  *      just scr_startup() was called!)
  220.  */
  221. void
  222. scr_end()
  223. {
  224. }
  225.  
  226. /*
  227.  * This is an internal function to print a buffer.  If flags==0 then
  228.  * print with paging and a final newline.  If flags & 1 then print
  229.  * without paging.  If flags & 2 then print up to but not including
  230.  * the last lineful, and return a pointer to it (a prompt).
  231.  */
  232. #define PB_NO_PAGING    (0x01)
  233. #define PB_PROMPT       (0x02)
  234.  
  235. static const char *
  236. scr_putbuf A3(FILE *, fp, int, flags, const char *, buf)
  237. {
  238.     const char *sp;
  239.     const char *ep;
  240.  
  241.     for (sp = buf; ;)
  242.     {
  243.         ep = chop_buf(sp, scr_columns);
  244.  
  245.         if ((*ep != '\0') || !(flags & PB_PROMPT))
  246.         {
  247.             const char *p;
  248.             int i;
  249.  
  250.             if (!(flags & PB_NO_PAGING) && (scr_lineco++ >= scr_lines))
  251.             {
  252.                 for (p = "--More--"; *p != '\0'; ++p)
  253.                     putchar(*p);
  254.                 setbuf(stdin, NULL);
  255.  
  256.                 while (((i = getchar()) != EOF) && (i != '\n'))
  257.                 {}
  258.  
  259.                 scr_lineco = 0;
  260.             }
  261.  
  262.             for (i=scr_indent; i>0; --i)
  263.                 putc(' ', fp);
  264.  
  265.             for (p = sp; p < ep; ++p)
  266.                 putc(*p, fp);
  267.  
  268.             putc('\n', fp);
  269.         }
  270.  
  271.         if (*ep == '\0')
  272.             break;
  273.  
  274.         sp = ep + 1;
  275.     }
  276.  
  277.     return (sp);
  278. }
  279.  
  280.  
  281. /*
  282.  * Function:    scr_putline()
  283.  *
  284.  * Arguments:
  285.  *      buffer          Line to be printed.
  286.  *
  287.  * Description:
  288.  *      This function is passed a nul-terminated string and it should
  289.  *      display the string on the terminal.  It will *not* contain a
  290.  *      newline character.
  291.  *
  292.  *      This function should perform whatever wrapping, paging, etc.
  293.  *      is necessary, print the string, and generate a final linefeed.
  294.  *
  295.  *      If the TI supports proportional-width fonts,
  296.  *      F2_IS_SET(B_FIXED_FONT) should be checked as appropriate.
  297.  *
  298.  *      If the TI supports scripting, F2_IS_SET(B_SCRIPTING) should be
  299.  *      checked as appropriate.
  300.  */
  301. void
  302. scr_putline A1(const char *, buffer)
  303. {
  304.     scr_putbuf(stdout, !gflags.paged, buffer);
  305.  
  306.     if (F2_IS_SET(B_SCRIPTING))
  307.         scr_putbuf(scr_fp, 1, buffer);
  308. }
  309.  
  310.  
  311. /*
  312.  * Function:    scr_putscore()
  313.  *
  314.  * Description:
  315.  *      This function prints the ti_location and ti_status strings
  316.  *      if it can and if status line printing is enabled.
  317.  */
  318. void
  319. scr_putscore()
  320. {
  321. }
  322.  
  323.  
  324. /*
  325.  * Function:    scr_putsound()
  326.  *
  327.  * Arguments:
  328.  *      number      sound number to play
  329.  *      action      action to perform
  330.  *      volume      volume to play sound at
  331.  *      argc        number of valid arguments
  332.  *
  333.  * Description:
  334.  *      This function plays the sound specified if it can; if not it
  335.  *      prints a line to that effect.
  336.  *
  337.  *      If the `argc' value is 1, then the we play `number' of beeps
  338.  *      (usually the ^G character).
  339.  *
  340.  *      If `argc' >1, the `action' argument is used as follows:
  341.  *
  342.  *          2:  play sound file
  343.  *          3:  stop playing sound file
  344.  *          4:  free sound resources
  345.  *
  346.  *      If `argc' >2, the `volume' argument is between 1 and 8 and is
  347.  *      a volume to play the sound at.
  348.  */
  349. void
  350. scr_putsound A4(int, number, int, action, int, volume, int, argc)
  351. {
  352.     if (argc == 1)
  353.     {
  354.         while (number--)
  355.             putchar('\a');
  356.     }
  357.     else if (argc == 3 && action == 2)
  358.     {
  359.         char buf[81];
  360.  
  361.         sprintf(buf, "Sound not supported! (number $%02x, volume %d)",
  362.                 number, volume);
  363.  
  364.         scr_putmesg(buf, 0);
  365.     }
  366. }
  367.  
  368.  
  369. /*
  370.  * Function:    scr_putmesg()
  371.  *
  372.  * Arguments:
  373.  *      buffer      message string to be printed.
  374.  *      is_err      1 if message is an error message, 0 if it's not.
  375.  *
  376.  * Description:
  377.  *      This function prints out a message from the interpreter, not
  378.  *      from the game itself.  Often these are errors (IS_ERR==1)
  379.  *      but not necessarily.
  380.  */
  381. void
  382. scr_putmesg A2(const char *, buffer, Bool, is_err)
  383. {
  384.     static char *buf = "";
  385.     int blen;
  386.  
  387.     blen = strlen(buffer);
  388.     if (strlen(buf) < blen + 12)
  389.     {
  390.         if (strlen(buf) == 0)
  391.             buf = xmalloc(blen + 13);
  392.         else
  393.             buf = xrealloc(buf, blen + 13);
  394.     }
  395.  
  396.     sprintf(buf, " [ %s%s ]",
  397.             is_err ? "ERROR: " : "",
  398.             buffer);
  399.  
  400.     scr_putline("");
  401.     scr_putline(buf);
  402.     scr_putline("");
  403. }
  404.  
  405.  
  406. /*
  407.  * Function:    scr_getstr()
  408.  *
  409.  * Description:
  410.  *      This is an internal function which performs the meat of
  411.  *      reading a string, throwing away the excess, etc.  It returns
  412.  *      the number of characters read.
  413.  *
  414.  * Notes:
  415.  *      This function is *not* a part of the terminal interface; it's
  416.  *      just an interal helper function.
  417.  */
  418. static int
  419. scr_getstr A3(const char *, prompt, int, length, char *, buffer)
  420. {
  421.     int c;
  422.  
  423.     fputs(prompt, stdout);
  424.     fflush(stdout);
  425.  
  426.     buffer[0] = '\0';
  427.     buffer[length-2] = '\0';
  428.     fgets(buffer, length, stdin);
  429.  
  430.     /*
  431.      * If there's more beyond the max length of our buffer, read
  432.      * it in and throw it away...
  433.      */
  434.     if ((buffer[length-2] != '\0')
  435.         && (buffer[length-2] != '\n')
  436.         && ((c = getchar()) != EOF)
  437.         && (c != '\n'))
  438.     {
  439.         fputs(" [ Input line too long.  Flushing: `", stdout);
  440.         do
  441.         {
  442.             putchar(c);
  443.         }
  444.         while (((c = getchar()) != EOF) && (c != '\n'));
  445.  
  446.         scr_putline("' ]");
  447.     }
  448.     else
  449.     {
  450.         /*
  451.          * Punt the last \n...
  452.          */
  453.         length = strlen(buffer) - 1;
  454.         buffer[length] = '\0';
  455.     }
  456.  
  457.     return (length);
  458. }
  459.  
  460.  
  461. /*
  462.  * Function:    scr_getline()
  463.  *
  464.  * Arguments:
  465.  *      prompt    - prompt to be printed
  466.  *      length    - total size of BUFFER
  467.  *      buffer    - buffer to return nul-terminated response in
  468.  *
  469.  * Returns:
  470.  *      # of chars stored in BUFFER
  471.  *
  472.  * Description:
  473.  *      Reads a line of input and returns it.  Handles all "special
  474.  *      operations" such as readline history support, shell escapes,
  475.  *      etc. invisibly to the caller.  Note that the returned BUFFER
  476.  *      will be at most LENGTH-1 chars long because the last char will
  477.  *      always be the nul character.
  478.  *
  479.  *      If the command begins with ESC_CHAR then it's an interpreter
  480.  *      escape command; call ti_escape() with the rest of the line,
  481.  *      then ask for another command.
  482.  *
  483.  * Notes:
  484.  *      May print the STATUS buffer more than once if necessary (i.e.,
  485.  *      a shell escape messed up the screen, a history listing was
  486.  *      generated, etc.).
  487.  */
  488. int
  489. scr_getline A3( const char *, prompt,
  490.                 int,          length,
  491.                 char *,       buffer )
  492. {
  493.     const char *pp;
  494.     const char *esc_str = ESC_CHAR;
  495.     int i;
  496.  
  497.     for (;;)
  498.     {
  499.         scr_lineco = 0;
  500.  
  501.         /*
  502.          * Print all the prompt except the last line
  503.          */
  504.         pp = scr_putbuf(stdout, PB_PROMPT, prompt);
  505.  
  506.         i = scr_getstr(pp, length, buffer);
  507.  
  508.         if (!i || (*buffer != *esc_str))
  509.             break;
  510.  
  511.         ti_escape(&buffer[1]);
  512.     }
  513.  
  514.     if (F2_IS_SET(B_SCRIPTING))
  515.     {
  516.         pp = scr_putbuf(scr_fp, PB_NO_PAGING|PB_PROMPT, prompt);
  517.         fputs(pp, scr_fp);
  518.         scr_putbuf(scr_fp, PB_NO_PAGING, buffer);
  519.     }
  520.  
  521.     return (i);
  522. }
  523.  
  524.  
  525. /*
  526.  * Function:    scr_window()
  527.  *
  528.  * Arguments:
  529.  *      size      - 0 to delete, non-0 means create with SIZE.
  530.  *
  531.  * Description:
  532.  *      Causes a status window to be created if supported by the
  533.  *      terminal interface; note this function won't be called unless
  534.  *      F1_SETB(B_STATUS_WIN) is invoked in scr_begin().
  535.  *
  536.  * Notes:
  537.  */
  538. void
  539. scr_window A1(int, size)
  540. {
  541. }
  542.  
  543.  
  544. /*
  545.  * Function:    scr_set_win()
  546.  *
  547.  * Arguments:
  548.  *      win       - 0==select text window, 1==select status window
  549.  *
  550.  * Description:
  551.  *      Selects a different window.  This function won't be called
  552.  *      unless call F1_SETB(B_STATUS_WIN) in scr_begin().
  553.  *
  554.  * Notes:
  555.  */
  556. void
  557. scr_set_win A1(int, win)
  558. {
  559. }
  560.  
  561.  
  562. /*
  563.  * Function:    scr_open_sf()
  564.  *
  565.  * Arguments:
  566.  *      length    - total size of BUFFER
  567.  *      buffer    - buffer to return nul-terminated filename in
  568.  *      type      - SF_SAVE     opening the file to save into
  569.  *                  SF_RESTORE  opening the file to restore from
  570.  *                  SF_SCRIPT   opening a file for scripting
  571.  *
  572.  * Returns:
  573.  *      FILE* - reference to the opened file, or
  574.  *      NULL  - errno==0: operation cancelled, else error opening file
  575.  *
  576.  * Description:
  577.  *      Obtains the name of the file to be opened for writing (if
  578.  *      TYPE==SF_SAVE or SF_SCRIPT) or reading (if TYPE==SF_RESTORE),
  579.  *      opens the file with fopen(), and returns the FILE*.
  580.  *
  581.  *      The name of the file should be stored in BUFFER.  Upon initial
  582.  *      calling BUFFER contains a possible default filename.
  583.  *
  584.  *      if LENGTH==0 then don't ask the user for a name, just use
  585.  *      BUFFER.  This means, for example, we got the -r option to
  586.  *      restore the file.
  587.  *
  588.  *      If the fopen() fails just return NULL: if errno!=0 then an
  589.  *      error will be printed.
  590.  *
  591.  * Notes:
  592.  *      History is turned off here (why would anyone want it?)
  593.  */
  594. FILE *
  595. scr_open_sf A3( int, length, char *, buffer, int, type )
  596. {
  597. #define FN_PROMPT       "Filename (or q)"
  598. #define MAX_PATH        1024
  599.  
  600.     FILE *fp;
  601.     char prompt[MAX_PATH+sizeof(FN_PROMPT)+6];
  602.     char *cp, *p;
  603.     int len;
  604.  
  605.     if (length == 0)
  606.     {
  607.         errno = 0;
  608.         return (fopen(buffer,
  609.                       type==SF_RESTORE ? "rb" : type==SF_SAVE ? "wb" : "w"));
  610.     }
  611.  
  612.     cp = xmalloc(length);
  613.  
  614.  retry:
  615.     scr_lineco=0;
  616.  
  617.     sprintf(prompt, "%s [%s] ? ", FN_PROMPT, buffer);
  618.  
  619.     len = scr_getstr(prompt, length, cp);
  620.  
  621.     /*
  622.      * Remove any excess whitespace from the end of the string.
  623.      * If the input is really empty, then use the initial buffer.
  624.      * If not copy over the string into the buffer.
  625.      */
  626.     for (p = &cp[len-1]; len && isspace(*p); --len, --p)
  627.     {}
  628.     p[1] = '\0';
  629.  
  630.     fp = NULL;
  631.     errno = 0;
  632.  
  633.     if ((len == 1) && (cp[0] == 'q'))
  634.         goto done;
  635.  
  636.     if (len)
  637.         strcpy(buffer, cp);
  638.  
  639.     len = strlen(buffer);
  640.  
  641.     /*
  642.      * Open the file for reading.  If we're saving and it already
  643.      * exists then ask if the user wants to overwrite it.  If not then
  644.      * ask for another name.
  645.      */
  646.     if (len)
  647.     {
  648.         fp = fopen(buffer, "rb");
  649.         if (type != SF_RESTORE)
  650.         {
  651.             if (fp != NULL)
  652.             {
  653.                 char over_p[MAX_PATH+40];
  654.  
  655.                 fclose(fp);
  656.                 sprintf(over_p,
  657.                         "File `%s' exists: overwrite (y/n/q)[y]? ",
  658.                         buffer);
  659.  
  660.                 if (scr_getstr(over_p, length, cp))
  661.                     if (cp[0] == 'q')
  662.                     {
  663.                         fp = NULL;
  664.                         goto done;
  665.                     }
  666.                     else if (cp[0] != 'y')
  667.                         goto retry;
  668.             }
  669.  
  670.             fp = fopen(buffer, type==SF_SAVE ? "wb" : "w");
  671.         }
  672.     }
  673.  
  674.  done:
  675.     free(cp);
  676.  
  677.     if (type == SF_SCRIPT)
  678.         scr_fp = fp;
  679.  
  680.     return (fp);
  681. }
  682.  
  683.  
  684. /*
  685.  * Function:    scr_close_sf()
  686.  *
  687.  * Arguments:
  688.  *      filenm    - name of file just processed
  689.  *      fp        - FILE* to open saved file
  690.  *      type      - SF_SAVE     closing a saved game file
  691.  *                  SF_RESTORE  closing a restored game file
  692.  *                  SF_SCRIPT   closing a scripting file
  693.  *
  694.  * Description:
  695.  *      This function will be called immediately after a successful
  696.  *      save or restore of a game file, so that if the interface needs
  697.  *      to perform any actions related to the saved game it may.  It
  698.  *      will also be called when the interpreter notices that
  699.  *      scripting has been turned off.  It should at least close the
  700.  *      file.
  701.  *
  702.  *      This function will only be called if the save/restore of the
  703.  *      game succeeded; if it fails the file will be closed by the
  704.  *      interpreter.
  705.  */
  706. void
  707. scr_close_sf A3( const char *, filenm, FILE *, fp, int, type )
  708. {
  709.     fclose(fp);
  710. }
  711.